/* STANDARD LIBRARY */
#include<cstdio>
#include<stdlib.h>
#include<iostream>
#include<string>
#include<math.h>

/* GSL LIBRARY */
#include<gsl/gsl_vector.h>
#include<gsl/gsl_multiroots.h>
#include<gsl/gsl_spline.h>

/* ADDITIONAL LIBRARY */
#include"constants.h" // constants

/* DECLATATIONS */
#ifndef DECLARATIONS_supToGSL
#define DECLARATIONS_supToGSL

/* Parameters to Multiroot Solver */
class Parameters
{
private:
	unsigned int n;
	double *p;
public:
	Parameters(unsigned int _n) : n(_n), p(NULL) {}
	Parameters(unsigned int _n, double *_p) : n(_n), p(_p) {}
	~Parameters() {};

	// for definition see supToGSL.cpp file
	int set(unsigned int _n, double *_p);
	double* get();
	unsigned int dim();
	int print();
	double & operator[](unsigned int el);
	const double & operator[](unsigned int el) const;

};

/* Multiroot Solver */
class MultirootSolver
{
protected:
	const size_t n; // number of equations to solve
	int status; // -1 mean that solveFor hasn't done yet
	size_t iter;
	gsl_vector *gslX0; // start point

	virtual int print() = 0; // change in future to without = 0;

public:
	MultirootSolver(unsigned int _n);
	virtual ~MultirootSolver();
	virtual int solveFor(Parameters *Par, Parameters *X0) = 0;
	virtual Parameters* getResult() = 0; // change in future to without = 0
};

/* Multiroot Solver - metod 1 - f*/
typedef int (*functionF)(const gsl_vector*, void*, gsl_vector*);

class MultirootSolverF : public MultirootSolver
{
private:
	functionF f;
	gsl_multiroot_function gslF; // set of functions to solve
	const gsl_multiroot_fsolver_type *gslT;
	gsl_multiroot_fsolver *gslS; // result there (final point)

	int print();

public:
	// for definition see supToGSL.cpp file
	MultirootSolverF(functionF _f, unsigned int _n);
	~MultirootSolverF();

	virtual int printResult();
	int solveFor(Parameters *Par, Parameters *X0);
	Parameters* getResult();
};

/* Multiroot Solver - metod 2 - fdf*/
typedef int (*functionDF)(const gsl_vector*, void*, gsl_matrix*);
typedef int (*functionFDF)(const gsl_vector*, void*, gsl_vector*, gsl_matrix*);

class MultirootSolverFDF : public MultirootSolver
{
private:
	functionF f;
	functionDF df;
	functionFDF fdf;
	gsl_multiroot_function_fdf gslFDF; // set of functions to solve
	const gsl_multiroot_fdfsolver_type *gslT;
	gsl_multiroot_fdfsolver *gslS; // result there (final point)

	int print();

public:
	// for definition see supToGSL.cpp file
	MultirootSolverFDF(functionF _f, functionDF _df, functionFDF _fdf, unsigned int _n);
	~MultirootSolverFDF();

	int solveFor(Parameters *Par, Parameters *X0);
	Parameters* getResult();
};
#endif
